<template>
    <jb-page>
        <template #title>Function Call 测试</template>
        <template #opt>
            <jb-btn type="primary" ghost :drawerComponent="FunctionManagement"
                    :drawerComponentProps="{selectList:selectList}" :drawerArgs="{width: '1200px'}"
                    @drawerYesClick="handleDrawerYesClick">选择Function资源
            </jb-btn>
        </template>
        <template #default="{list,tableStartIndex}">
            <n-layout has-sider style="height: 100%">
                <n-layout class="left-content">
                    <div style="height: 100%" class="chat_panel" ref="chatContainer">
                        <div v-if="showAISetting"
                             style="display:flex;flex-direction:column;position: absolute;bottom: 140px;right: 80px;width: 360px;background-color:#FFF;border-radius: 16px;box-shadow: 0px 0px 6px 1px rgba(0,0,0,0.1);padding: 18px 16px">
                            <div
                                style="width: 100%;display: flex;justify-content: space-between;align-items: center;border-bottom: 1px solid #ccc;padding: 10px">
                                <span style="font-size: 18px">聊天设置</span>
                                <div style="cursor: pointer" @click="showAISetting=false">
                                    <jb-icon :local="true" icon="iconamoon:close-bold" style="font-size: 20px;color: #333"></jb-icon>
                                </div>

                            </div>

                            <n-form style="margin-top: 24px" ref="formRef" :model="defaultFuncAIConfig"
                                    label-placement="top" label-width="120" require-mark-placement="right-hanging">
                                <n-form-item label="选择AI模型" path="name">
                                    <jb-select url="aiResource/listAllEnabledType" labelField="name" placeholder="请选择AI模型"
                                               valueField="sn" v-model:value="defaultFuncAIConfig.model"></jb-select>
                                </n-form-item>
                                <n-form-item label="MaxToken值" path="sn">
                                    <div class="flex-col" style="width: 100%">
                                        <n-input-number round
                                                        v-model:value="defaultFuncAIConfig.maxTokens" placeholder="请输入MaxToken值"
                                                        max="8192">
                                            <template #suffix>
                                                tokens
                                            </template>
                                        </n-input-number>
                                        <span class="text-gray-400 font-12 pad-5 bg-gray-50 rounded-lg mt-1">范围: 1-8192</span>
                                    </div>

                                </n-form-item>
                                <n-form-item label="Temperature" path="">
                                    <n-input-number round style="width: 100%"
                                                    v-model:value="defaultFuncAIConfig.temperature" :precision="2"
                                                    placeholder="请输入Temperature值">
                                    </n-input-number>
                                </n-form-item>
                                <n-form-item label="Top P" path="">
                                    <div style="display: flex;flex-direction: column">
                                        <n-slider v-model:value="defaultFuncAIConfig.topP" :step="0.1" :max="1"/>
                                        <span
                                            class="text-gray-400 font-12 pad-5 bg-gray-50 rounded-lg mt-1">调节句子生成的多样性，值越大生成的内容越丰富多样，但它和Temperature只能设置一个</span>
                                    </div>
                                </n-form-item>
                                <n-form-item label="Top K" path="">
                                    <div style="display: flex;flex-direction: column">
                                        <n-input-number round style="width: 100%" :precision="0"
                                                        v-model:value="defaultFuncAIConfig.topK" placeholder="请输入TopK值" max="100">
                                        </n-input-number>
                                        <span
                                            class="text-gray-400 font-12 pad-5 bg-gray-50 rounded-lg mt-1">限制每次生成时考虑的词汇数量，值越大创造性越强。该选项不是所有大模型都支持。</span>
                                    </div>
                                </n-form-item>


                            </n-form>
                        </div>
                    </div>
                </n-layout>

                <n-layout-sider bordered collapse-mode="width" :collapsed-width="0" :width="300"
                                content-style="padding: 16px;border-left:1px solid rgb(241 241 241)">
                    <div class="selected-items-container">
                        <div class="selected-header">
                            <span>已选择 {{ selectList.length }} 项</span>
                        </div>
                        <div class="selected-content">
                            <template v-if="selectList.length">
                                <div v-for="item in selectList" :key="item.id" class="selected-item">
                                    <span class="item-text">{{ item.name || item.briefInfo }}</span>
                                    <n-button circle size="tiny" type="error" class="delete-btn"
                                              @click="handleRemoveItem(item)">
                                        <template #icon>
                                            <jb-icon :local="true" icon="iconamoon:close-bold"></jb-icon>
                                            <!--                      <n-icon>-->
                                            <!--                        <close/>-->
                                            <!--                      </n-icon>-->
                                        </template>
                                    </n-button>
                                </div>
                            </template>
                            <div v-else class="empty-text">
                                暂无选中项
                            </div>
                        </div>
                    </div>
                </n-layout-sider>
            </n-layout>
        </template>
    </jb-page>
</template>

<script setup>
import markdownit from 'markdown-it'
import {
    onActivated, onDeactivated,
    onBeforeUnmount,
    onMounted,
    ref,
    watch
} from "vue";
import {
    JBoltApi
} from "@/service/request/index.js";
import AiChat from "@/components/_builtin/jb-ai-chat/index.js";

import {
    storeToRefs
} from "pinia";
import {
    useWebSocketStore
} from "@/stores/websocket.js";

import FunctionManagement from "./cpns/param-management/index.vue"
import {useMessage} from "naive-ui";
import texmath  from 'markdown-it-texmath'
import katex from 'katex';
const webSocketStore = storeToRefs(useWebSocketStore())

const md = markdownit({
    html: true,
    breaks: true,
    linkify: true,
    typographer: true
});
md.use(texmath, {
    engine: katex,
    delimiters: [
        "dollars", "brackets"
    ]
})

const appId = ref(2)
const tableRef = ref(null)
const chatContainer = ref(null)
const chatInstance = ref(null)
const chatState = ref({
    pageSize: 20,
    hasMore: false,
    startId: null,

})
const showAISetting = ref(false)

//默认当前的ai模型的对象
const defaultFuncAIConfig = ref({
    systemRole: '',
    maxTokens: 2000,
    topP: 0,
    topK: 0,
    model: '',
    useContext: false,
    stream: false,
    temperature: 0.5

})
const message = useMessage()
//默认当前的session对象
const currentSession = ref({})
//默认的functioncall的ids配置对象
const defaultFuncIdsConfig = ref({
    functions: []
})
//监听当前的session对象
watch(() => currentSession.value, (newV) => {
    if (newV) {
        if (chatInstance.value) {
            chatInstance.value.destroy();
        }
        if (chatContainer.value) {
            chatState.value = {
                pageSize: 20,
                hasMore: false,
                startId: null,
            }
            loadChatInstance()
        }
    }

})
watch(() => webSocketStore.ws.value, () => {
    console.debug("websock重连")
    if (chatInstance.value) {
        chatInstance.value.updateWebSocket(webSocketStore.ws.value)
    }
})

watch(() => chatContainer.value, (newV) => {
    if (newV && !chatInstance.value) {
        loadChatInstance()
    }
})
//监听Ai模型的配置
// watch(() => defaultFuncAIConfig.value, (async (newVal, oldVal) => {
//   if (newVal?.id != oldVal?.id) return;
//   // console.log("AI配置变动：", JSON.stringify(newVal));
//   await JBoltApi.tryPost('/aiAppConfig/updateConfigByKey', {
//     linkType: "session",
//     linkId: currentSession.value.id,
//     configKey: "llmConfig",
//     configValue: JSON.stringify(newVal)
//   });
// }), {
//   deep: true
// })
//监听functioniCall的配置
watch(() => defaultFuncIdsConfig.value, (async (newVal, oldVal) => {
    if (newVal?.id != oldVal?.id) return;
    // console.log("functioncall配置变动：", JSON.stringify(newVal));
    await JBoltApi.tryPost('/aiAppConfig/updateConfigByKey', {
        linkType: "session",
        linkId: currentSession.value.id,
        configKey: "funcCallConfig",
        configValue: JSON.stringify(newVal)
    });
}), {
    deep: true
})

const selectList = ref([])

function handleRemoveItem(item) {
    // console.log(item,"移除item")
    // 从选中列表中移除
    selectList.value = selectList.value.filter(i => i.id !== item.id)

    // 取消表格中对应行的选中状态
    const $table = tableRef.value
    if ($table) {
        $table.setCheckboxRow([item], false)
    }

    defaultFuncIdsConfig.value.functions = selectList.value.map(item => item.id)
}

function handleDrawerYesClick({
                                  componentRef,
                                  close
                              }) {

    componentRef.submit((data) => {
        selectList.value = data;
        defaultFuncIdsConfig.value.functions = data.map(item => item.id);
        close();
    })

}

function loadChatInstance() {
    //初始化aichat
    chatInstance.value = new AiChat(chatContainer.value, {
            // websocketUrl: 'ws://192.168.31.118:8013/ws',
            websocketInstance: webSocketStore.ws.value,
            app: appId.value,
            showAvatar: false,
            sessionId: currentSession.value.id,
            global: null,
            onMsgReceive: (data) => {
            },
            onMsgSend: (msg) => {
            },
            onMsgToDelete: async (id) => {
                console.debug("删除消息", id)
                let {
                    result
                } = await JBoltApi.get(`/aiAppMessage/delMsgById/${id}`)
                console.log(result, "----")
                if (result.code == 0) {
                    message.success("删除成功");
                    return true;
                } else {
                    // message.error("删除失败");
                    return false;
                }
            },
            onSettingClick: (chatInsence) => {
                showAISetting.value = !showAISetting.value
            },
            onMarkdownRender: (markdown) => {
                return md.render(markdown);
            },
            onHistoryLoad: async (startId, global) => {
                // console.log("加载历史记录...", startId, chatState.value.hasMore)
                if (chatState.value.hasMore == false) return;
                let {
                    result
                } = await JBoltApi.get('/aiAppMessage/getListByPage', {
                    sessionId: currentSession.value.id,
                    startId,
                    pageSize: chatState.value.pageSize,
                })

                let {
                    list,
                    totalPage
                } = result.data
                chatState.value.hasMore = chatState.value.pageSize == list?.length;
                // console.log("加载历史记录开始", list)
                if (!list || !list.length) {
                    // console.log(currentChat.value.hasMsg)
                    return false;
                }
                console.debug("加载历史记录完成...", list)
                chatState.value.hasMsg = true;
                return list.map(item => {
                    return {
                        id: item.id,
                        flag: item.role == "user" ? item.id : item.linkId,
                        data: {
                            role: item.role,
                            format: item.role == 'assistant' ? "markdown" : "",
                            content: {
                                text: item.content,
                            },
                            reference: item.reference,
                            errorMsg: item.errorMsg,
                        },

                        createTime: item.createTime
                    }
                })
            }

        },
    )
}


watch(() => useWebSocketStore().ws.value, (newV) => {

    if (chatContainer.value && newV) {
        chatInstance.value.updateWebSocket(useWebSocketStore().ws.value)
    }
})

function addSession() {
    JBoltApi.tryPost('/aiAppSession/add', {
        name: '新的function Call会话',
        appId: appId.value,
        config: {
            "llmConfig": defaultFuncAIConfig.value,
            "funcCallConfig": defaultFuncIdsConfig.value,
        }
    }).then((res) => {
        currentSession.value = res.data;
    });
}


onMounted(() => {
    // 添加会话
    addSession();
})
onBeforeUnmount(() => {
    if (chatInstance.value) {
        chatInstance.value.destroy()
    }
})
onActivated(() => {
    if (!chatInstance.value && currentSession.value.id) {
        // console.log("aiChat组件被激活,当前被选中的id:" + currentSession.value.id)
        chatState.value.hasMore = true
        loadChatInstance()
    }
})

onDeactivated(() => {
    if (chatInstance.value) {
        chatInstance.value.destroy()
        chatInstance.value = null;
    }
})
</script>


<style scoped lang="scss">
.left-content {
    display: flex;
    flex-direction: column;
    height: 100%;

}

.left-content:deep(.n-layout-scroll-container) {
    display: flex;
    flex-direction: column;
}

.selected-items-container {
    height: 100%;
    display: flex;
    flex-direction: column;
}

.selected-header {
    padding: 8px 0;
    font-weight: 500;
    border-bottom: 1px solid var(--n-border-color);
    margin-bottom: 12px;
}

.selected-content {
    flex: 1;
    overflow-y: auto;
}

.selected-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 12px;
    margin-bottom: 8px;
    border-radius: 4px;
    background-color: var(--n-card-color);
    transition: all 0.3s;
}

.selected-item:hover {
    background-color: var(--n-table-header-color);
}

.item-text {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    margin-right: 8px;
}

.delete-btn {
    opacity: 0.8;
}

.delete-btn:hover {
    opacity: 1;
}

.empty-text {
    text-align: center;
    color: var(--n-text-color-disabled);
    padding: 32px 0;
}
</style>